package main

import (
	"fmt"
	"time"
)

// https://refactoringguru.cn/design-patterns/chain-of-responsibility

type Context struct {
	app   *Application
	url   string
	index int
}

func NewContext(app *Application, url string) *Context {
	return &Context{app: app, url: url, index: -1}
}

func (ctx *Context) Next() {
	ctx.index++
	for ctx.index >= 0 && ctx.index < len(ctx.app.chain) {
		ctx.app.chain[ctx.index](ctx)
		ctx.index++
	}
}

func (ctx *Context) Abort() {
	ctx.index = -3
}

type HandleFunc func(ctx *Context)

type HandleChain []HandleFunc

type Application struct {
	chain HandleChain
}

func (app *Application) Handle(url string) {
	NewContext(app, url).Next()
}

func (app *Application) Use(handle HandleFunc) {
	app.chain = append(app.chain, handle)
}

func main() {
	app := new(Application)

	app.Use(func(ctx *Context) {
		defer func(n time.Time) {
			fmt.Println("Logger:", ctx.url)
		}(time.Now())

		ctx.Next()
	})

	app.Use(func(ctx *Context) {
		if ctx.url == "abort" {
			fmt.Println("Abort")
			ctx.Abort()
			return
		}
		fmt.Println("Call:", ctx.url)
	})

	app.Handle("index")
	fmt.Println("-----")
	app.Handle("abort")
}
